﻿//
//根据 鱼刺的  CookieEasy 改的 可能 会在自己的理解上有一些不足之处
//
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;

namespace ShareHelper.HttpHelper
{
    /// <summary>
    /// Cookie  管理类
    /// </summary>
    public class CookieEasy
    {
        /// <summary>
        /// Cookie 删除标记
        /// </summary>
        private const string Deleted = "Deleted";

        /// <summary>
        ///  获取 或 设置 Cookie
        /// </summary>
        public string Cookies
        {
            get { return ToString(); }
            set
            {
                DCookies.Clear();//dictionary(字典) 清除之前的数据
                //设置 内容不为空
                if (!string.IsNullOrEmpty(value))
                    Up(value);// 添加Cookie
            }
        }

        private ConcurrentDictionary<string, string> DCookies { get; } = new ConcurrentDictionary<string, string>();

        /// <summary>
        /// 删除内部Cookies中的Cookie
        /// </summary>
        /// <param name="Cookies">单个或多个Cookie或Cookie名称
        /// （例如：abc 或是 abc=123 或是 或是 abc; def;g 或是 abc=123; def=456;g=nima;id）</param>
        /// <returns></returns>
        public bool Del(string Cookies)
        {
            //删全部空空 分好分割
            string[] sArray = Cookies.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);//冒号分割
            int time = 0;//计数器
            foreach (string item in sArray)//遍历数组
            {
                int Start = item.IndexOf("=");//寻找=号位置
                //有等于号 等于号前面的是 Name 没有等于号 直接就是 Name
                string Name = Start > 0 ? item.Substring(0, Start) : item;
                if (DCookies.TryRemove(Name.Trim(), out string value))
                    time++;// 尝试进行删除 有成功删除 计数器增加
            }
            return time > 0;//计数器不为零 有成功 删除
        }

        /// <summary>
        /// 获取内部Cookies中的某个Cookie （必须在AutoCookies模式1下使用)
        /// </summary>
        /// <param name="Name">Cookie名称</param>
        /// <returns></returns>
        public string Get(string Name)
        {
            //三元运算符 存在返回 Value  不存在 返回空字符串 跟上面的代码差不多吧
            if (DCookies.TryGetValue(Name, out string value))
            {
                return value;
            }
            return String.Empty;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns> Cookies</returns>
        public override string ToString()
        {
            //讲DCookies 映射到一个新的表单中
            return String.Join("; ", DCookies.ToArray().Select(a => $"{a.Key}={a.Value}"));
        }

        /// <summary>
        /// 添加或替换Cookie到内部Cookies （忽略空键值的cookie并删除同名的原cookie）
        /// </summary>
        /// <param name="Cookies">要添加的单个或多个Cookie （例如：abc=123 或是 abc=123; def=456;g=nima ）</param>
        /// <returns></returns>
        public bool Up(string Cookies)
        {
            //冒号分割 分割数组 不包含空字符串
            string[] sArray = Cookies.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
            int time = 0;// for循环遍历字符串数组 添加单个Cookie 添加成功计数器 加一
            for (int i = 0; i < sArray.Length; i++)
                if (Add(sArray[i])) time++;
            return time > 0;//计数器 大于零 有成功添加
        }

        /// <summary>
        /// 处理并更新内部Cookies（参数为原始协议头） （忽略空键值的cookie并删除同名的原cookie）
        /// </summary>
        /// <param name="Headers">带Set-Cookie的原始协议头文本</param>
        /// <returns></returns>
        public bool UpH(WebHeaderCollection Headers)
        {
            string[] Cookie = Headers.GetValues(HeaderKey.SetCookie);//尝试取出 包含 Cookies
            if (Cookie == null)
                return false;//// 为空未有Cookie 头添加
            int time = 0;//成功添加计数
            foreach (string item in Cookie)//遍历Cookie
            {
                int length = item.IndexOf(";");//寻找分割符;
                length = length > 0 ? length : item.Length;//有;符号 符号前面的是Cookie 没有符号一整行都是Cookie
                if (Add(item.Substring(0, length)))
                    time++;// 添加单个cookie 字符串 添加成功 计数器 + 1
            }
            return time > 0;//计数大于零 有成功添加Cookies
        }

        /// <summary>
        /// 添加coolie 对
        /// </summary>
        /// <param name="cookie">cookie =  "Name=Value"</param>
        /// <returns></returns>
        private bool Add(string cookie)
        {
            cookie = cookie.Trim();//删除左边空白文本 删首空
            if (string.IsNullOrEmpty(cookie))
                return false;//判断参数是否为空 cookie 行为空 直接返回
            int Start = cookie.IndexOf("=");//寻找等号分隔符
            if (Start == -1)
                return false;// 判断等号是否存在 等号不存在直接返回
            string Name = cookie.Substring(0, Start++);//取出cookie 名称
            string Value = cookie.Substring(Start);//取出cookie 值
            // value 为空 为删除Cookie 尝试进行删除 删除成功 代表已更新
            if (string.IsNullOrEmpty(Value))
                return DCookies.TryRemove(Name, out Value);
            //判断是否是删除标记
            if (Value.StartsWith(Deleted, StringComparison.OrdinalIgnoreCase))
                return false;//删除标记返回
            DCookies.AddOrUpdate(Name, Value, (a, b) => Value);//添加新的内容
            return true;
        }
    }
}